<script setup lang="ts">
import { onMounted, ref } from 'vue'

defineExpose({ checkCode, resetCode })
const canvasCode = ref<string>('')

const { length, noise, fontFamily } = defineProps({
  width: {
    type: Number,
    default: 120,
  },
  height: {
    type: Number,
    default: 40,
  },
  length: {
    type: Number,
    default: 4,
  },
  noise: {
    type: Number,
    default: 5,
  },
  fontFamily: {
    type: String,
    default: 'sans-serif',
  },
})

onMounted(() => {
  canvasCode.value = createCode('canvasCode', length)
})

function getNewCode() {
  canvasCode.value = createCode('canvasCode', length)
}

function createCode(id: string, length: number) {
  let checkCode = produceCode(length)
  let dom = document.getElementById(id) as HTMLCanvasElement
  if (!dom) {
    return
  }
  let canvas = dom.getContext('2d')
  canvas.textBaseline = 'middle' // 设置在绘制文本时使用的当前文本基线
  canvas.fillStyle = randomColor(60, 255) //设置填充绘画的颜色
  canvas.fillRect(0, 0, dom.width, dom.height) // 绘制矩形

  canvas.font = 0.8 * dom.height + `px ${fontFamily}`
  for (let i = 0; i < checkCode.length; i++) {
    let char = checkCode.charAt(i)
    canvas.fillStyle = randomColor(60, 180)
    canvas.shadowOffsetY = randomNum(-3, 3)
    canvas.shadowBlur = randomNum(-3, 3)
    canvas.shadowColor = 'rgba(0, 0, 0, 0.3)'
    //如果验证码超出了canvas画布，说明画布宽度不够，请扩大宽度或者减少验证码字符量
    let x = (dom.width / (checkCode.length + 1)) * (i + 0.5)
    let y = dom.height / 2
    let deg = randomNum(-20, 20)
    /**设置旋转角度和坐标原点*/
    canvas.translate(x, y)
    canvas.rotate((deg * Math.PI) / 180)

    canvas.fillText(char, 0, 0)

    /**恢复旋转角度和坐标原点*/
    canvas.rotate((-deg * Math.PI) / 180)
    canvas.translate(-x, -y)
  }

  /**随机干扰线随机出现*/
  for (let i = 0; i < randomNum(1, checkCode.length * noise); i++) {
    canvas.strokeStyle = randomColor(40, 180)
    canvas.beginPath()
    canvas.moveTo(randomNum(0, dom.width), randomNum(0, dom.height))
    canvas.lineTo(randomNum(0, dom.width), randomNum(0, dom.height))
    canvas.stroke()
  }

  /**绘制干扰点*/
  for (let i = 0; i < dom.width / 6; i++) {
    canvas.fillStyle = randomColor(0, 255)
    canvas.beginPath()
    canvas.arc(
      randomNum(0, dom.width),
      randomNum(0, dom.height),
      1,
      0,
      2 * Math.PI,
    )
    canvas.fill()
  }

  return checkCode
}

function produceCode(length = 4) {
  let code = ''
  let random = [
    1,
    2,
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    'A',
    'B',
    'C',
    'D',
    'E',
    'F',
    'G',
    'H',
    'J',
    'K',
    'L',
    'M',
    'N',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    'V',
    'W',
    'X',
    'Y',
    'Z',
  ]
  for (let i = 0; i < length; i++) {
    let index = randomNum(0, random.length)
    code += random[index]
  }
  return code
}

//产生随机数字
function randomNum(min: number, max: number) {
  return Math.floor(Math.random() * (max - min) + min)
}

//产生随机颜色
function randomColor(min: number, max: number) {
  let r = randomNum(min, max)
  let g = randomNum(min, max)
  let b = randomNum(min, max)
  return 'rgb(' + r + ',' + g + ',' + b + ')'
}

function checkCode(code: string): boolean {
  return code.toLowerCase() === canvasCode.value.toLowerCase()
}

function resetCode() {
  getNewCode()
}
</script>

<template>
  <canvas
    id="canvasCode"
    :width="width + 'px'"
    :height="height + 'px'"
    @click="getNewCode()"
  >
    您的浏览器不支持 HTML5 canvas 标签。
  </canvas>
</template>

<style scoped></style>
